import sys,time
from qasync import QEventLoop, asyncSlot
from PyQt5.QtWidgets import (QApplication, QWidget, QVBoxLayout, QHBoxLayout, 
                            QPushButton, QLabel, QLineEdit, QGroupBox)
from PyQt5.QtCore import Qt
import asyncio
from tqsdk import TqApi, TqAuth, TqAccount, TqSim,TqKq
from PyQt5.QtGui import QIcon, QFont
from threading import Thread
from db_manager import *

class MainWindow(QWidget):
    def __init__(self):
        super().__init__()
        self.api=None
        self.running=False
        self.main_layout = QVBoxLayout()
        
        # 设置窗口图标
        self.setWindowIcon(QIcon(r'E:\Private.Net\WorkShop\tqsdk\Tq\App.png'))
        
        # 主窗口样式
        self.setStyleSheet("""
            background-color: #f5f5f5;
            font-family: 'Microsoft YaHei';
        """)
        
        # 创建顶部标题
        title = QLabel("天勤量化交易系统")
        title.setAlignment(Qt.AlignCenter)
        title.setStyleSheet("""
            font-size: 24px;
            font-weight: bold;
            color: #333;
            padding: 20px;
        """)
        self.main_layout.addWidget(title)
        
        # 创建账户连接区域
        account_group = QGroupBox("账户连接")
        account_layout = QVBoxLayout()
        
        self.button = QPushButton("连接天勤账户")
        self._setup_button_style(self.button)
        account_layout.addWidget(self.button)
        
        account_group.setLayout(account_layout)
        self.main_layout.addWidget(account_group)
        
        # 创建交易功能区域
        # 在交易功能区域添加新按钮
        trade_group = QGroupBox("交易功能")
        trade_layout = QHBoxLayout()
        
        self.button2 = QPushButton("查询账户持仓")
        self._setup_button_style(self.button2)
        trade_layout.addWidget(self.button2)
        
        # 添加启动策略交易按钮
        self.start_strategy_btn = QPushButton("启动策略交易")
        self._setup_button_style(self.start_strategy_btn)
        trade_layout.addWidget(self.start_strategy_btn)
        
        trade_group.setLayout(trade_layout)
        self.main_layout.addWidget(trade_group)
        
        # 设置主布局
        self.setLayout(self.main_layout)
        
        # 连接信号槽
        self.button.clicked.connect(lambda: self.connect_tq())
        self.button2.clicked.connect(lambda: self.my_position())
        self.start_strategy_btn.clicked.connect(lambda: self.async_start())
        
        # 窗口大小
        self.resize(800, 600)
    
    def _setup_button_style(self, button):
        """统一设置按钮样式"""
        button.setStyleSheet("""
            QPushButton {
                background-color: #4CAF50;
                border: none;
                color: white;
                padding: 12px 24px;
                text-align: center;
                text-decoration: none;
                font-size: 16px;
                margin: 4px 2px;
                border-radius: 4px;
                min-width: 120px;
            }
            QPushButton:hover {
                background-color: #45a049;
            }
            QPushButton:pressed {
                background-color: #3e8e41;
            }
        """)

    @asyncSlot()
    async def connect_tq(self):
        """异步方法：连接天勤账户"""
        print("连接天勤账户...")
        tq_kq = TqKq()  # 创建快期模拟账户实例
        self.api = TqApi(account=tq_kq, auth=TqAuth("cps168", "alibaba999"))  # 使用账户和认证信息创建天勤API实例
        self.macc=self.api.get_account()  # 获取账户信息
        print("连接成功,账户可用资金为：",self.macc.available)  # 打印账户可用资金信息
        self.running=True
    
    @asyncSlot()
    async def my_position(self):
        async def query_pos():
            """异步方法：查询账户持仓"""
            if self.api:
                print("查询账户持仓...")
                # 修改为查询所有持仓而不是特定合约
                positions = self.api.get_position()  # 获取所有持仓
                while self.running:
                    deadline = time.time() + 1
                    self.api.wait_update(deadline=deadline)
                    for symbol, pos in positions.items():
                        print(f"时间：{time.strftime('%Y-%m-%d %H:%M:%S')}",
                             f"{symbol} 持仓信息:", 
                             f"多头:{pos.pos_long}", 
                             f"空头:{pos.pos_short}")
        Thread(target=asyncio.run, args=(query_pos(),)).start()

    @asyncSlot()
    async def async_start(self):
        async def _process_product(symbol):
            """单个品种处理协程"""
            print(f"开始处理品种: {symbol}")  # 添加日志
            try:
                klines = self.api.get_kline_serial(symbol, 300, 500)        
                while self.running:
                    # deadline = time.time() + 1
                    # self.api.wait_update(deadline=deadline)         
                    print(f"{symbol} 正在运行...", flush=True)  # 添加flush确保及时输出
                    if self.api.is_changing(klines.iloc[-1], "datetime"):
                        if not klines.close.iloc[-1]:
                            print("K线已变化")
                            q = (3*klines.close + klines.low + klines.open + klines.high) / 6
                            ma_values = _calculate_ma(q)
                            short_ma = ma_values['ma']
                            ema_7 = ma_values['ema']
                            
                            position = self.api.get_position(symbol)
                            
                            # 平空仓逻辑
                            if short_ma[-2] > ema_7[-2]:  
                                if position.pos_short > 0:
                                    self.api.insert_order(symbol, direction="BUY", offset="CLOSE", 
                                                    volume=position.pos_short)
                            # 开多仓逻辑
                            if position.pos_long == 0 and position.pos_short == 0 and short_ma[-3] < ema_7[-3] and short_ma[-2] > ema_7[-2]:
                                self.api.insert_order(symbol, direction="BUY", offset="OPEN", 
                                                volume=lots)
                                
                            # 平多仓逻辑
                            if short_ma[-2] < ema_7[-2]:  
                                if position.pos_long > 0:
                                    self.api.insert_order(symbol, direction="SELL", offset="CLOSE", 
                                                    volume=position.pos_long)
                            # 开空仓逻辑
                            if position.pos_long == 0 and position.pos_short == 0 and short_ma[-3] > ema_7[-3] and short_ma[-2] < ema_7[-2]:
                                self.api.insert_order(symbol, direction="SELL", offset="OPEN", 
                                                volume=lots)

            except Exception as e:
                print(f"处理品种 {symbol} 时出错: {str(e)}")
            finally:
                print(f"结束处理品种: {symbol}")  # 添加日志
        def _calculate_ma(q):
            """自定义权重计算（与原版完全一致）"""
            weights = np.arange(26, 0, -1)
            ma = []
            q_array = np.array(q)
            for i in range(len(q_array)):
                if i < 26:
                    ma.append(np.nan)
                    continue
                window = q_array[i-26:i+1]
                ma.append(np.dot(window, weights) / 351)
            
            ema_7 = EMA(pd.Series(ma), 7)
            return {'ma': ma, 'ema': ema_7.tolist()}
        """启动策略"""
        # tq_kq = TqKq()
        # api = TqApi(account=tq_kq, auth=TqAuth("cps168", "alibaba999"))
        lots = 1  # 每笔交易的手数        
        
        # 从数据库获取监控品种
        conn = connect_db()
        monitored_products = get_monitored_products(conn)
        conn.close()
        
        # 为每个品种启动处理线程
        for symbol in monitored_products:
             Thread(target=asyncio.run,args=(_process_product(symbol[2]),)).start()

   
    #*************************************************************

    def closeEvent(self, event):
        """重写关闭事件，关闭前检查并关闭天勤API"""
        if self.api is not None:
            try:
                if self.running == True:
                    self.running=False
                    print("业务处理循环已关闭！")
                #print("正在关闭天勤API连接...")
                #self.api.close()  # 关闭天勤API
                # loop = asyncio.get_event_loop()
                # loop.call_soon_threadsafe(self.api.close())
            except Exception as e:
                print("关闭天勤量化api出错",str(e))
            finally:
                pass
        event.accept()  # 接受关闭事件
    
    @asyncSlot()
    async def HelloWorld():
        print("Hello World!")
        
if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = MainWindow()
    window.setWindowTitle("天勤量化交易系统")
    window.resize(700,600)
    window.show()
    loop = QEventLoop(app)
    asyncio.set_event_loop(loop)
    sys.exit(app.exec())